Yelp案例:The Neo4j Graph Algorithms User Guide v3.5

第2章Yelp示例

本章介绍Yelp开放数据集,它用于举例说明Neo4j图形算法的工作原理。

2.1 Yelp开放数据集

自2013年以来,Yelp.com一直在运行Yelp数据集挑战 ; 鼓励人们探索和研究Yelp开放数据集竞赛。截至第10轮挑战,该数据集包含:

  • 近500万条评论
  • 超过110万用户
  • 超过150,000家企业
  • 12个大都市区

自推出以来,该数据集已经变得非常流行,有数百篇关于它的学术论文。它具有结构良好,高度关系的数据,因此是一个真实的数据集,用于展示Neo4j和图算法。

我们将说明如何在朋友的社交网络上使用图算法,以及如何创建和分析推断图(例如,投影评论共现图,或基于他们的评论的用户之间的相似性)。

2.2 数据

在挑战的第10轮中,数据集包括:

  • 156,639家企业
  • 有关企业的用户提示1,005,693
  • 4,736,897条用户的评价
  • 共有9,489,337位用户
  • 朋友关系35,444,850

您可以通过填写Yelp网站上的表单以JSON格式下载数据集。有6个JSON文件可供使用(详细文档)。出于本示例的目的,我们将忽略照片和签到文件,因为它们与我们的分析无关。

https://www.yelp.com/dataset/download

我们将从其余文件创建知识图,并将使用APOC插件帮助我们在Neo4j中导入和批处理数据。根据您的设置,导入可能需要一些时间(user.json文件包含大约1000万人的社交朋友网络的数据)。虽然review.json的大小更大,但它主要由代表实际审核的文本组成,因此导入速度会更快。我们也不需要实际的文本,只需要关于它们的元数据。例如,导入了撰写评论的人员以及某个企业的评级方式的元数据,但文本本身不会被导入。

2.3 图模型

img
我们的图表包含User标记的节点,与其他用户建立friends关系。用户还会撰写有关商家的评论reviews和建议tips。所有元数据都存储为节点的属性,但业务类别除外,这些类别由标记的单独节点表示Category。

图模型总是取决于我们好的构建方式。我们的应用是使用图算法分析(推断)网络。如果我们将我们的图用作推荐引擎,我们可能会构建一个不同的图形模型。

2.4 引入(import)

1、定义图模式graph schema(约束/索引)。

1
2
3
CALL apoc.schema.assert(
{Category:['name']},
{Business:['id'],User:['id'],Review:['id']});

2、加载 businesses.

1
2
3
4
5
6
7
8
9
10
CALL apoc.periodic.iterate("
CALL apoc.load.json('file:///dataset/business.json') YIELD value RETURN value
","
MERGE (b:Business{id:value.business_id})
SET b += apoc.map.clean(value, ['attributes','hours','business_id','categories','address','postal_code'],[])
WITH b,value.categories as categories
UNWIND categories as category
MERGE (c:Category{id:category})
MERGE (b)-[:IN_CATEGORY]->(c)
",{batchSize: 10000, iterateList: true});

3、加载 tips.

1
2
3
4
5
6
7
CALL apoc.periodic.iterate("
CALL apoc.load.json('file:///dataset/tip.json') YIELD value RETURN value
","
MATCH (b:Business{id:value.business_id})
MERGE (u:User{id:value.user_id})
MERGE (u)-[:TIP{date:value.date,likes:value.likes}]->(b)
",{batchSize: 20000, iterateList: true});

4、加载 reviews.

1
2
3
4
5
6
7
8
9
10
11
CALL apoc.periodic.iterate("
CALL apoc.load.json('file:///dataset/review.json')
YIELD value RETURN value
","
MERGE (b:Business{id:value.business_id})
MERGE (u:User{id:value.user_id})
MERGE (r:Review{id:value.review_id})
MERGE (u)-[:WROTE]->(r)
MERGE (r)-[:REVIEWS]->(b)
SET r += apoc.map.clean(value, ['business_id','user_id','review_id','text'],[0])
",{batchSize: 10000, iterateList: true});

5、加载 users.

1
2
3
4
5
6
7
8
9
10
11
CALL apoc.periodic.iterate("
CALL apoc.load.json('file:///dataset/user.json')
YIELD value RETURN value
","
MERGE (u:User{id:value.user_id})
SET u += apoc.map.clean(value, ['friends','user_id'],[0])
WITH u,value.friends as friends
UNWIND friends as friend
MERGE (u1:User{id:friend})
MERGE (u)-[:FRIEND]-(u1)
",{batchSize: 100, iterateList: true});

2.5 网络概述

2.5.1社交网络

2.5.1.1 全局图表统计

节点:8981389
关系:35444850
弱连接(Weakly connected components):18512
最大WCC中的节点(Nodes in largest WCC):8938630
最大的WCC边缘(Edges in largest WCC):35420520
三角计数(Triangle count) :
平均聚类系数(Average clustering coefficient):
图形直径(最长最短路径)Graph diameter (longest shortest path):

2.5.1.2 本地图表统计

使用apoc计算本地统计信息。

1
2
3
4
5
MATCH (u:User)
RETURN avg(apoc.node.degree(u,'FRIEND')) as average_friends,
stdev(apoc.node.degree(u,'FRIEND')) as stdev_friends,
max(apoc.node.degree(u,'FRIEND')) as max_friends,
min(apoc.node.degree(u,'FRIEND')) as min_friends

平均朋友人数:7.47
朋友标准差:46.96
最少朋友数:1
最大朋友数:14995

2.5.2 展现评论 co-occurence 网络图

通过 co-occurence 网络图找出哪些商家经常被相同的用户评论

a review co-occurence between businesses

1
2
3
4
5
6
7
8
9
10
11
12
13
14
CALL apoc.periodic.iterate('
MATCH (b1:Business)
WHERE size((b1)<-[:REVIEWS]->()) > 10 AND b1.city="Las Vegas"
RETURN b1
','
MATCH (b1)<-[:REVIEWS]-(r1)
MATCH (r1)<-[:WROTE]-(u)
MATCH (u)-[:WROTE]->(r2)
MATCH (r2)-[:REVIEWS]->(b2)
WHERE id(b1) < id(b2) AND b2.city="Las Vegas"
WITH b1, b2, COUNT(*) AS weight where weight > 5
MERGE (b1)-[cr:CO_OCCURENT_REVIEWS]-(b2)
ON CREATE SET cr.weight = weight
',{batchSize: 1});

2.5.3 投影相似评论图数据

我们可以通过在它们之间投射评论相似性网络来尝试找到类似的用户组。我们的想法是从拥有超过10条评论的用户开始,并查找已评论超过10种常见商家的所有用户对。我们这样做是为了过滤掉数据不足的用户。我们可以做类似的事情来过滤掉评论过每个商家的用户(可能是机器人,或者非常无聊的人!)。

一旦我们找到用户对,我们通过使用余弦相似度计算它们的评论相似度,并且仅在余弦相似度大于0时才创建关系; 有时也称为硬相似性(hard similarity)。我们这样做以至于我们不会得到每个用户都连接在一起的完整图结构。大多数社区检测算法在完整图表中表现不佳。用户对之间的余弦相似性被保存为关系属性,并且可以用作图算法中的权重使用。由于关系的方向没有语义值,因此投影图的模型是无向的。

投影相似性图表的投影通常用于建议中; 类似的用户是根据评论评分计算的,因此我们可以向用户推荐类似用户喜欢的内容。

创建相似评论图结构

1
2
3
4
5
6
7
8
9
CALL apoc.periodic.iterate(
"MATCH (p1:User) WHERE size((p1)-[:WROTE]->()) > 5 RETURN p1",
"
MATCH (p1)-[:WROTE]->(r1)-->()<--(r2)<-[:WROTE]-(p2)
WHERE id(p1) < id(p2) AND size((p2)-[:WROTE]->()) > 10
WITH p1,p2,count(*) as coop, collect(r1.stars) as s1, collect(r2.stars) as s2 where coop > 10
WITH p1,p2, apoc.algo.cosineSimilarity(s1,s2) as cosineSimilarity WHERE cosineSimilarity > 0
MERGE (p1)-[s:SIMILAR_REVIEWS]-(p2) SET s.weight = cosineSimilarity"
, {batchSize:100, parallel:false,iterateList:true});

应用文献:
http://snap.stanford.edu/class/cs224w-2015/projects_2015/Predicting_Yelp_Ratings_Using_User_Friendship_Network_Information.pdf
http://snap.stanford.edu/class/cs224w-2013/projects2013/cs224w-038-final.pdf